package com.djf.djfcs.esService;

import com.djf.djfcs.entity.es.MyData;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.elasticsearch.action.admin.indices.delete.DeleteIndexRequest;
import org.elasticsearch.action.get.GetRequest;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchRequest;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.support.master.AcknowledgedResponse;
import org.elasticsearch.action.update.UpdateRequest;
import org.elasticsearch.action.update.UpdateResponse;
import org.elasticsearch.client.RequestOptions;
import org.elasticsearch.client.RestHighLevelClient;
import org.elasticsearch.client.indices.CreateIndexRequest;
import org.elasticsearch.client.indices.GetIndexRequest;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.xcontent.XContentType;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.builder.SearchSourceBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.util.*;

/**
 * @Author 26393
 * @Date 2025/7/1 18:44
 * @Version 1.0
 */
@Service // 标记这是一个服务组件
public class MyDataService {

    private final RestHighLevelClient esClient; // Elasticsearch 高级 REST 客户端
    private final ObjectMapper objectMapper; // Jackson 用于对象和JSON之间的转换
    private static final String INDEX_NAME = "my_data"; // 索引名

    @Autowired // 自动注入客户端和ObjectMapper
    public MyDataService(RestHighLevelClient esClient, ObjectMapper objectMapper) {
        this.esClient = esClient;
        this.objectMapper = objectMapper;
    }

    /**
     * 创建索引及映射
     * @return 是否创建成功
     * @throws IOException IO异常
     */
    public boolean createMyDataIndex() throws IOException {
        // 检查索引是否存在
        GetIndexRequest request = new GetIndexRequest(INDEX_NAME);
        boolean exists = esClient.indices().exists(request, RequestOptions.DEFAULT);
        if (exists) {
            System.out.println("索引 '" + INDEX_NAME + "' 已存在。");
            return false;
        }

        // 构建创建索引请求
        CreateIndexRequest createRequest = new CreateIndexRequest(INDEX_NAME);
        createRequest.settings(Settings.builder()
                .put("index.number_of_shards", 1) // 设置主分片数量
                .put("index.number_of_replicas", 0) // 设置副本分片数量
        );

        // 定义索引映射 (字段类型)
        createRequest.mapping(
                "{\n" +
                        "  \"properties\": {\n" +
                        "    \"title\": { \"type\": \"text\" },\n" +
                        "    \"content\": { \"type\": \"text\" },\n" +
                        "    \"category\": { \"type\": \"keyword\" },\n" +
                        "    \"views\": { \"type\": \"integer\" },\n" +
                        "    \"isPublished\": { \"type\": \"boolean\" },\n" + // 与Java对象字段名保持一致
                        "    \"publishDate\": { \"type\": \"date\", \"format\": \"yyyy-MM-dd'T'HH:mm:ss'Z'\" } \n" + // 日期格式
                        "  }\n" +
                        "}",
                XContentType.JSON // 指定内容类型为 JSON
        );

        // 执行创建索引操作
        AcknowledgedResponse createIndexResponse = esClient.indices().create(createRequest, RequestOptions.DEFAULT);
        System.out.println("索引创建确认: " + createIndexResponse.isAcknowledged());
        return createIndexResponse.isAcknowledged();
    }

    /**
     * 索引文档 (插入或更新文档)
     * @param myData 要索引的文档对象
     * @return 索引到的文档ID
     * @throws IOException IO异常
     */
    public String indexMyData(MyData myData) throws IOException {
        // 如果文档没有指定ID，则自动生成一个UUID
        if (myData.getId() == null || myData.getId().isEmpty()) {
            myData.setId(UUID.randomUUID().toString());
        }
        // 如果没有设置发布日期，则自动设置为当前时间
        if (myData.getPublishDate() == null) {
            myData.setPublishDate(new Date());
        }

        // 构建索引请求
        IndexRequest request = new IndexRequest(INDEX_NAME)
                .id(myData.getId()) // 指定文档ID
                .source(objectMapper.writeValueAsString(myData), XContentType.JSON); // 将Java对象转为JSON字符串作为源

        // 执行索引操作
        IndexResponse response = esClient.index(request, RequestOptions.DEFAULT);
        System.out.println("文档已索引，ID: " + response.getId());
        return response.getId();
    }

    /**
     * 根据ID获取文档
     * @param id 文档ID
     * @return 找到的文档对象，如果不存在则返回 null
     * @throws IOException IO异常
     */
    public MyData getMyDataById(String id) throws IOException {
        GetRequest getRequest = new GetRequest(INDEX_NAME, id); // 构建获取请求
        GetResponse getResponse = esClient.get(getRequest, RequestOptions.DEFAULT); // 执行获取操作

        if (getResponse.isExists()) { // 检查文档是否存在
            Map<String, Object> sourceAsMap = getResponse.getSourceAsMap(); // 获取源数据Map
            MyData myData = objectMapper.convertValue(sourceAsMap, MyData.class); // 将Map转为Java对象
            myData.setId(getResponse.getId()); // 从响应中设置文档ID
            return myData;
        } else {
            return null;
        }
    }

    /**
     * 搜索文档
     * @param queryText 搜索关键字 (用于标题和内容)
     * @param category 分类 (精确匹配)
     * @param minViews 最小浏览量
     * @param maxViews 最大浏览量
     * @return 匹配的文档列表
     * @throws IOException IO异常
     */
    public List<MyData> searchMyData(String queryText, String category, Integer minViews, Integer maxViews) throws IOException {
        SearchRequest searchRequest = new SearchRequest(INDEX_NAME); // 构建搜索请求，指定索引
        SearchSourceBuilder searchSourceBuilder = new SearchSourceBuilder(); // 构建搜索源构建器
        BoolQueryBuilder boolQuery = QueryBuilders.boolQuery(); // 构建布尔查询

        if (queryText != null && !queryText.isEmpty()) {
            // 全文搜索 title 和 content 字段
            boolQuery.must(QueryBuilders.multiMatchQuery(queryText, "title", "content"));
        }

        if (category != null && !category.isEmpty()) {
            // 精确匹配 category.keyword 字段 (因为它是 keyword 类型)
            boolQuery.filter(QueryBuilders.termQuery("category.keyword", category));
        }

        if (minViews != null || maxViews != null) {
            // 范围查询 views 字段
            boolQuery.filter(QueryBuilders.rangeQuery("views")
                    .gte(minViews) // 大于等于
                    .lte(maxViews)); // 小于等于
        }

        searchSourceBuilder.query(boolQuery); // 将布尔查询设置到搜索源中
        searchSourceBuilder.from(0); // 设置分页起始位置
        searchSourceBuilder.size(10); // 设置每页返回数量
        // searchSourceBuilder.sort("publishDate", SortOrder.DESC); // 可以设置排序

        searchRequest.source(searchSourceBuilder); // 将搜索源设置到搜索请求中

        SearchResponse searchResponse = esClient.search(searchRequest, RequestOptions.DEFAULT); // 执行搜索操作

        List<MyData> myDataList = new ArrayList<>();
        searchResponse.getHits().forEach(hit -> { // 遍历搜索结果
            try {
                MyData myData = objectMapper.readValue(hit.getSourceAsString(), MyData.class); // 将JSON字符串转为Java对象
                myData.setId(hit.getId()); // 从搜索结果中设置文档ID
                myDataList.add(myData);
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
        return myDataList;
    }

    /**
     * 更新文档的部分字段
     * @param id 文档ID
     * @param updates 要更新的字段及其值 (Map 格式)
     * @return 更新的文档ID
     * @throws IOException IO异常
     */
    public String updateMyData(String id, Map<String, Object> updates) throws IOException {
        UpdateRequest updateRequest = new UpdateRequest(INDEX_NAME, id)
                .doc(updates, XContentType.JSON); // 只更新传入的字段，以JSON格式

        UpdateResponse updateResponse = esClient.update(updateRequest, RequestOptions.DEFAULT); // 执行更新操作
        System.out.println("文档已更新，ID: " + updateResponse.getId() + ", 结果: " + updateResponse.getResult());
        return updateResponse.getId();
    }

    /**
     * 根据ID删除文档
     * @param id 文档ID
     * @return 是否删除成功
     * @throws IOException IO异常
     */
    public boolean deleteMyData(String id) throws IOException {
        org.elasticsearch.action.delete.DeleteRequest deleteRequest = new org.elasticsearch.action.delete.DeleteRequest(INDEX_NAME, id);
        org.elasticsearch.action.delete.DeleteResponse deleteResponse = esClient.delete(deleteRequest, RequestOptions.DEFAULT); // 执行删除操作
        System.out.println("文档已删除，ID: " + deleteResponse.getId() + ", 结果: " + deleteResponse.getResult());
        return deleteResponse.getResult().equals(org.elasticsearch.action.delete.DeleteResponse.Result.DELETED);
    }

    /**
     * 删除整个索引
     * @return 是否删除成功
     * @throws IOException IO异常
     */
    public boolean deleteMyDataIndex() throws IOException {
        DeleteIndexRequest request = new DeleteIndexRequest(INDEX_NAME); // 构建删除索引请求
        AcknowledgedResponse deleteResponse = esClient.indices().delete(request, RequestOptions.DEFAULT); // 执行删除操作
        System.out.println("索引删除确认: " + deleteResponse.isAcknowledged());
        return deleteResponse.isAcknowledged();
    }
}
